﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using Microsoft.Practices.Unity;
using TagLib;
using System.Collections.ObjectModel;
using System.Collections;
using System.Threading;
using System.Windows.Threading;
using System.Windows;

namespace MP3Ganizer.Modules.FileView.ViewModels
{
    /// <summary>
    /// ViewModel du FileView
    /// </summary>
    public class FileViewListVM : INotifyPropertyChanged, IFileViewListVM
    {
        #region Fields
        private ObservableCollection<IFileViewVM> _fileList;
        private ObservableCollection<string> _artistList;
        private ObservableCollection<string> _albumList;
        private readonly IUnityContainer container;
        private string _sourceDir;
        private string _destinationDir;
        private int _tagFilesLoaded;
        private int _fileCount;
        private int _fileTotal;
        #endregion

        #region IFileViewMainVM Members

        /// <summary>
        /// Vue principale
        /// </summary>
        public MP3Ganizer.Modules.FileView.Views.IFileViewMainV MainView { get; private set; }
        public ObservableCollection<IFileViewVM> FileList
        {
            get { return _fileList; }
            set { _fileList = value;
            OnPropertyChanged("FileList");
            }
        }

        public ObservableCollection<string> ArtistList
        {
            get {
                return _artistList;
            }
        }

        public ObservableCollection<string> AlbumList
        {
            get
            {
                return _albumList;
            }
        }

        public double Percentage
        {
            get 
            {
                double p = _fileTotal == 0 ? 0 : _fileCount * 10000 / _fileTotal;
                p = p / 100;
                return p; 
            }
        }

        public string PercentageStr
        {
            get
            {
                double p = _fileTotal == 0 ? 0 : _fileCount * 10000 / _fileTotal;
                p = p / 100;
                return p.ToString("N2");
            }
        }

        #endregion

        /// <summary>
        /// Constructeur. Les paramètres sont pré-remplis par le UnityContainer.
        /// </summary>
        /// <param name="container"></param>
        /// <param name="mainView"></param>
        public FileViewListVM(IUnityContainer container, MP3Ganizer.Modules.FileView.Views.IFileViewMainV mainView)
        {
            _fileList = new ObservableCollection<IFileViewVM>();
            this.container = container;
            this.MainView = mainView;
            this.MainView.SetModel(this);
            this.container.Resolve<Microsoft.Practices.Composite.Events.IEventAggregator>().GetEvent<MP3Ganizer.Events.User.UserActionEvent>().Subscribe(OnUserAction, Microsoft.Practices.Composite.Presentation.Events.ThreadOption.UIThread, true);
        }

        private void OnUserAction(MP3Ganizer.Events.User.UserActionEventArgs e)
        {
            if (e.Action == MP3Ganizer.Common.Enums.UserAction.LoadFileTree)
            {
                if (e.Data is KeyValuePair<string, string>)
                {
                    KeyValuePair<string, string> pathes = (KeyValuePair<string, string>)e.Data;
                    _sourceDir = pathes.Key;
                    _destinationDir = pathes.Value;
                    Load();             
                }
            }
        }

        public void Load()
        {
            FileList.Clear();
            ObservableCollection<object> tagList = new ObservableCollection<object>();
            tagList.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(tagList_CollectionChanged);
            _fileCount = 0;
            ThreadPool.QueueUserWorkItem(delegate
            {
                MP3Ganizer.Services.Files.FilesServices.GetTagsFromDirectory(tagList, _sourceDir, out _fileTotal);
                Application.Current.Dispatcher.BeginInvoke(new DispatcherOperationCallback(OptimizeFileListMethod), DispatcherPriority.Normal, 0);
            });
            OnPropertyChanged("FileList");
        }
        public void RemoveFile(IFileViewVM x)
        {
            FileList.Remove((IFileViewVM)x);
            OnPropertyChanged("FileList");
        }
        public void ReLoad()
        {
            List<IFileViewVM> newList = FileList.ToList<IFileViewVM>();
            ThreadPool.QueueUserWorkItem(delegate
            {
                newList.ForEach(x => 
                {
                    if(!x.IsSourceFileExists())
                        Application.Current.Dispatcher.BeginInvoke(new DispatcherOperationCallback(RemoveFileFromList), DispatcherPriority.Normal, x);
                }
                );
                Application.Current.Dispatcher.BeginInvoke(new DispatcherOperationCallback(OptimizeFileListMethod), DispatcherPriority.Normal, 0);
            });    
        }
        
        public object RemoveFileFromList(object file)
        {
            FileList.Remove((IFileViewVM)file);
            OnPropertyChanged("FileList");
            return null;
        }

        delegate void AddTagFiles(System.Collections.Specialized.NotifyCollectionChangedEventArgs e);
        void tagList_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            try
            {
                Application.Current.Dispatcher.BeginInvoke(new DispatcherOperationCallback(AddTagFilesMethod), DispatcherPriority.Normal, e);
            }
            catch
            {

            }

        }
        private object AddTagFilesMethod(object obj)
        {
            System.Collections.Specialized.NotifyCollectionChangedEventArgs e = (System.Collections.Specialized.NotifyCollectionChangedEventArgs)obj;
            if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
            {
                IEnumerator myEnum = e.NewItems.GetEnumerator();
                while (myEnum.MoveNext())
                    _fileList.Add(new FileViewVM(container, myEnum.Current, _destinationDir, _sourceDir));
            }
            if (_tagFilesLoaded == 10)
            {
                OnPropertyChanged("FileList");
                _tagFilesLoaded = 0;
            }
            else
                _tagFilesLoaded++;
            _fileCount++;
            OnPropertyChanged("Percentage");
            return null;
        }
        private object OptimizeFileListMethod(object o)
        {
            Dictionary<string, string> artistAlbums = new Dictionary<string, string>();
            Dictionary<string, string> albums = new Dictionary<string, string>();
            _fileList.ToList<IFileViewVM>().ForEach(x =>
            {
                if (!string.IsNullOrEmpty(x.ArtisteAlbum) && !artistAlbums.Keys.Contains(x.ArtisteAlbum) && x.ArtisteAlbum.ToLower() != "artist")
                    artistAlbums.Add(x.ArtisteAlbum, x.Album);
                if (!string.IsNullOrEmpty(x.Album) && !albums.Keys.Contains(x.Album) && x.Album.ToLower() != "album")
                    albums.Add(x.Album, x.ArtisteAlbum);
            });
            _fileList.ToList<IFileViewVM>().ForEach(x =>
            {
                if (string.IsNullOrEmpty(x.Album))
                {
                    x.Album = albums.Keys.FirstOrDefault<string>(a => x.SourcePath.ToLower().Contains(a.ToLower()));
                    if (string.IsNullOrEmpty(x.ArtisteAlbum) && !string.IsNullOrEmpty(x.Album))
                        x.ArtisteAlbum = albums[x.Album];
                }
                if(string.IsNullOrEmpty(x.ArtisteAlbum))
                {
                    x.ArtisteAlbum = artistAlbums.Keys.FirstOrDefault<string>(aa => x.SourcePath.ToLower().Contains(aa.ToLower()));
                    if(string.IsNullOrEmpty(x.Album) && !string.IsNullOrEmpty(x.ArtisteAlbum))
                        x.Album = artistAlbums[x.ArtisteAlbum];
                }
            });
            _fileCount = _fileTotal;
            List<string> sorted = Services.Files.FilesServices.UpdateAndGetSortedArtistList(artistAlbums.Keys.ToList<string>());
            _artistList = new ObservableCollection<string>(sorted);
            sorted = Services.Files.FilesServices.UpdateAndGetSortedAlbumList(albums);
            _albumList = new ObservableCollection<string>(sorted);
            OnPropertyChanged("Percentage");
            Services.Files.FilesServices.CleanEmptyDirectories(_sourceDir);
            return null;
        }


        #region INotifyPropertyChanged Members
        /// <summary>
        /// Implémentation de INotifyPropertyChanged.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// Fonction de Raise de l'évènement PropertyChanged.
        /// </summary>
        /// <param name="PropertyName"></param>
        protected void OnPropertyChanged(string PropertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
            }
        }

        #endregion
    }
}
